﻿using Avalon.Core.MVC.Tempaltes;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Text;
using System.Web.Mvc;

namespace Avalon.Core.MVC.Helpers
{
    public static class ControlBuilder
    {
        public static string CreateInputControl(HtmlHelper htmlHelper, ModelMetadata propertyMetadata)
        {
            // If we're working with a field which should only be hidden just return the hidden field.
            if (!propertyMetadata.ShowForEdit) return string.Format(TemplateReader.InputHiddenTemplate, propertyMetadata.PropertyName, propertyMetadata.Model);

            // Get the error message
            ErrorMessage errorMessage = htmlHelper.ViewData.ModelState[propertyMetadata.PropertyName].GetErrorMessage();

            string controlTemplate = "";
            if (propertyMetadata.ModelType.IsEnum) controlTemplate = createEnumDropDown(htmlHelper, propertyMetadata);
            else controlTemplate = createSimpleControl(propertyMetadata);

            var result =  string.Format(
                Avalon.Core.MVC.Tempaltes.TemplateReader.InputControlTemplate, 
                errorMessage.ErrorClass, 
                propertyMetadata.PropertyName,
                propertyMetadata.GetDisplayName(), 
                controlTemplate, 
                errorMessage.Message);
            return result;
        }

        public static string CreateHiddenInputControl(this ModelMetadata propertyMetadata)
        {
            return string.Format(TemplateReader.InputHiddenTemplate, propertyMetadata.PropertyName, propertyMetadata.Model);
        }

        private static string createSimpleControl(ModelMetadata propertyMetadata)
        {
            //Try and parse the datatype of the current property in order to select the right control on the form.
            DataType dataType = DataType.Text;
            Enum.TryParse(propertyMetadata.DataTypeName, out dataType);

            bool readOnly = propertyMetadata.IsReadOnly;
            var readOnlyValue = readOnly ? "readonly='readonly'" : string.Empty;
            var enabledValue = readOnly ? "disabled='true'" : string.Empty;

            switch (dataType)
            {
                case DataType.Text:
                    return string.Format(TemplateReader.InputTextTemplate, propertyMetadata.PropertyName, propertyMetadata.Model, readOnlyValue);
                case DataType.Password:
                    return string.Format(TemplateReader.InputPasswordTemplate, propertyMetadata.PropertyName, propertyMetadata.PropertyName, propertyMetadata.Model, readOnlyValue);
                case DataType.MultilineText:
                    return string.Format(TemplateReader.InputMultilineTemplate, propertyMetadata.PropertyName, propertyMetadata.Model, readOnlyValue);
                case DataType.Date:
                    return string.Format(TemplateReader.InputDateTemplate, propertyMetadata.PropertyName, propertyMetadata.GetDateTimeValue(), enabledValue);
                default:
                    return string.Format(TemplateReader.InputTextTemplate, propertyMetadata.PropertyName, propertyMetadata.Model, readOnlyValue);
            }
        }

        private static string createEnumDropDown(HtmlHelper htmlHelper, ModelMetadata propertyMetadata)
        {
            //Create a string builder to return the result
            StringBuilder optionsBuilder = new StringBuilder();

            var values = Enum.GetValues(propertyMetadata.ModelType);
            for (int i = 0; i < values.Length; ++i)
            {
                var itemValue = values.GetValue(i).ToString();
                string selected = itemValue == propertyMetadata.Model.ToString() ? " selected='selected'" : "";
                optionsBuilder.AppendFormat(TemplateReader.InputSelectOptionTemplate, values.GetValue(i).ToString(), getEnumDescription(values.GetValue(i)), selected);
            }

            return string.Format(TemplateReader.InputSelectTemplate, propertyMetadata.PropertyName, optionsBuilder.ToString());
        }

        private static string getEnumDescription<TEnum>(TEnum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if ((attributes != null) && (attributes.Length > 0))
                return attributes[0].Description;
            else
                return value.ToString();
        }
    }
}
